/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER) || \
    defined(UMC_ENABLE_AVS_VIDEO_ENCODER)

#include "umc_avs_fusion_core.h"

#include "umc_avs_pic.h"
#include "umc_avs_processing_unit.h"

#include "umc_automatic_mutex.h"

namespace UMC
{

AVSFusionCore::AVSFusionCore(void)
{
    m_pPerformers = NULL;
    m_numThreads = 0;
    m_maxFrames = 0;

    memset(&m_seqHeader, 0, sizeof(m_seqHeader));
    memset(&m_picHeader, 0, sizeof(m_picHeader));

    m_numFrames = 0;
    m_curFrameNum = 0;

} // AVSFusionCore::AVSFusionCore(void)

AVSFusionCore::~AVSFusionCore(void)
{
    Release();

} // AVSFusionCore::~AVSFusionCore(void)

template <class T> static
void DeallocateList(T &list)
{
    while (list.GetHead())
    {
        delete list.ExtractHead();
    }

} // void DeallocateList(T list)

Status AVSFusionCore::Release(void)
{
    // peel slices off the frames
    Reset();

    // delete allocated frames
    DeallocateList(m_FreeFrames);

    // delete allocated slices
    DeallocateList(m_FreeSlices);

    // delete allocated slices
    DeallocateList(m_FreeMemory);

    // deinitialize list of performers
    if (m_pPerformers)
    {
        Ipp32u i;

        for (i = 0; i < m_numThreads; i += 1)
        {
            DeallocateList(m_pPerformers[i]);
        }

        delete [] m_pPerformers;
    }

    m_pPerformers = NULL;
    m_numThreads = 0;
    m_maxFrames = 0;

    memset(&m_seqHeader, 0, sizeof(m_seqHeader));
    memset(&m_picHeader, 0, sizeof(m_picHeader));

    m_numFrames = 0;
    m_curFrameNum = 0;

    return UMC_OK;

} // Status AVSFusionCore::Release(void)

#define AVS_ALLOCATE_PROCESSING_UNIT(name) \
    { \
        AVSListElement<AVSProcessingUnit> *pTemp; \
        pTemp = new name(); \
        if (NULL == pTemp) \
            return UMC_ERR_ALLOC; \
        pTemp->m_threadNumber = i; \
        m_pPerformers[i].AddToTail(*pTemp); \
        umcRes = pTemp->Init(&m_guard); \
        if (UMC_OK != umcRes) \
            return UMC_ERR_FAILED; \
    }

Status AVSFusionCore::Init(Ipp32u numThreads, BaseCodecParams *pParams)
{
    Status umcRes;

    // check error(s)
    if ((0 >= (Ipp32s) numThreads) ||
        (NULL == pParams))
        return UMC_ERR_INVALID_PARAMS;

    // release the object before initialization
    Release();

    // initialize the synchronization tool
    if (false == m_guard.IsInited())
    {
        umcRes = m_guard.Init();
        if (UMC_OK != umcRes)
            return umcRes;
    }

    // do initialization
    m_numThreads = numThreads;

    // allocate the performers array
    m_pPerformers = new AVSList<AVSProcessingUnit> [m_numThreads];
    if (NULL == m_pPerformers)
        return UMC_ERR_ALLOC;

    return UMC_OK;

} // Status AVSFusionCore::Init(Ipp32s numThreads, VideoDecoderParams *pParams)

Status AVSFusionCore::Reset(void)
{
    AutomaticMutex guard(m_guard.ExtractHandle());
    AVSListElement<AVSFrame> *pFrame;

    // just merge being processed frames into the free queue.
    m_FreeFrames.AddToTail(m_Frames);

    // reset being processed frames
    pFrame = m_FreeFrames.GetHead();
    while (pFrame)
    {
        // move slices and memory pieces into the corresponding lists
        PurgeFrame(pFrame);

        // get the next frame
        pFrame = pFrame->GetNext();
    }

    return UMC_OK;

} // Status AVSFusionCore::Reset(void)

AVSProcessingUnit *AVSFusionCore::GetTask(Ipp32u threadNum)
{
    AutomaticMutex guard(m_guard.ExtractHandle());
    AVSListElement<AVSProcessingUnit> *pPerf = m_pPerformers[threadNum].GetHead();
    Status umcRes = UMC_OK;

    do
    {
        // try one by one all performers from a queue
        if (pPerf->LoadJob(m_Frames.GetHead()))
            return pPerf;

        pPerf = pPerf->GetNext();

    } while (UMC_OK == umcRes);

    // it is an impossible case,
    // we always must get a performer
    return NULL;

} // AVSProcessingUnit *AVSFusionCore::GetTask(Ipp32u threadNum)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER) ||
